package com.hucsmn.examsystem.model;

import com.hucsmn.examsystem.common.AnswerSheet;
import com.hucsmn.examsystem.server.ExamServerException;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 考卷数据库。
 */
public class AnswerSheetDatabase implements Serializable {
    private static final long serialVersionUID = 6667876157866092532L;
    private final Map<Integer, AnswerSheet> answerSheets = new HashMap<>();
    private int nextId = 1;

    public AnswerSheetDatabase() {
    }

    public static AnswerSheetDatabase load(File file) throws IOException {
        try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
            Object obj = in.readObject();
            if (!(obj instanceof AnswerSheetDatabase)) {
                throw new ClassCastException();
            }
            AnswerSheetDatabase db = (AnswerSheetDatabase) obj;
            if (!db.validate()) {
                throw new ExamServerException("invalid answer sheet database");
            }
            return db;
        } catch (ClassNotFoundException | ClassCastException e) {
            throw new ExamServerException("not a user database");
        }
    }

    public synchronized AnswerSheet get(int id) {
        AnswerSheet answerSheet = answerSheets.get(id);

        if (answerSheet != null) {
            try {
                answerSheet = (AnswerSheet) answerSheet.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
        return answerSheet;
    }

    public synchronized int add(AnswerSheet answerSheet) {
        if (answerSheet == null) {
            throw new NullPointerException();
        }

        try {
            answerSheet = (AnswerSheet) answerSheet.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return -1;
        }

        answerSheet.setId(nextId);
        answerSheets.put(nextId, answerSheet);
        return nextId++;
    }

    public synchronized boolean delete(int id) {
        return answerSheets.remove(id) != null;
    }

    public synchronized boolean update(int id, AnswerSheet answerSheet) {
        if (answerSheet == null) {
            throw new NullPointerException();
        }

        try {
            answerSheet = (AnswerSheet) answerSheet.clone();
            answerSheet.setId(id);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return false;
        }

        return answerSheets.replace(id, answerSheet) != null;
    }

    public synchronized AnswerSheet[] select(int uid) {
        ArrayList<AnswerSheet> all = new ArrayList<>();

        try {
            for (AnswerSheet one : answerSheets.values()) {
                if (one.getUid() == uid) {
                    all.add((AnswerSheet) one.clone());
                }
            }
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
        return all.toArray(AnswerSheet[]::new);
    }

    public synchronized void save(File file) throws IOException {
        try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
            out.writeObject(this);
            out.flush();
        }
    }

    private boolean validate() {
        //TODO: validate AnswerSheet[].
        return true;
    }
}
